﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TextTemplating;
using System.Reflection;
using System.IO;
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.ServiceModel.DomainServices.Tools.TextTemplate;
using Microsoft.ServiceModel.DomainServices.Tools.TextTemplate.CSharpGenerators;
using CodeGenerationPipeline.Contracts;
using System.Collections;
using AbstraX.Contracts;

namespace CodeGenerationPipeline
{
    /// <summary>
    /// </summary>
    public class PipelineTemplateEngineHost : IPipelineTemplateEngineHost
    {
        private Type generatorType;
        private static bool bSkipErrors;
        public event EventHandler DebugCallback;
        public event OnGeneratorFileWithBuildPreBuildHandler OnGeneratorFileWithBuildPreBuild;
        public event OnGeneratorFileWithListPreBuildHandler OnGeneratorFileWithListPreBuild;
        public event OnGeneratorFileWithBuildPostBuildHandler OnGeneratorFileWithBuildPostBuild;
        public event OnGeneratorFileWithListPostBuildHandler OnGeneratorFileWithListPostBuild;

        public PipelineTemplateEngineHost()
        {
        }

        public PipelineTemplateEngineHost(Type generatorType)
        {
            this.generatorType = generatorType;
        }

        public void GenerateFile<TGeneratorType>(IElementBuild build, FileInfo fileInfo, string _namespace, Dictionary<string, object> extraValues = null)
        {
            this.generatorType = typeof(TGeneratorType);

            this.GenerateFile(build, fileInfo, _namespace, extraValues);
        }

        public void GenerateFile(IElementBuild build, FileInfo fileInfo, string _namespace, Dictionary<string, object> extraValues = null)
        {
            try
            {
                var generator = Activator.CreateInstance(generatorType);
                var session = new TextTemplatingSession();

                session["ElementBuild"] = build;
                session["Namespace"] = _namespace;

                if (extraValues != null)
                {
                    session["ExtraValues"] = extraValues;
                }

                if (DebugCallback != null)
                {
                    session["Callback"] = DebugCallback;
                }

                generatorType.GetProperty("Session").SetValue(generator, session, null);
                generatorType.GetMethod("Initialize").Invoke(generator, null);

                var output = (string) generatorType.GetMethod("TransformText").Invoke(generator, null);

                var stream = fileInfo.OpenWrite();
                var writer = new StreamWriter(stream);

                writer.Write(output);
                writer.Flush();

                writer.Close();
                stream.Close();
            }
            catch (Exception ex)
            {
                Debugger.Break();
            }
        }

        public void GenerateFile<TGeneratorType>(FileInfo fileInfo, string _namespace, Dictionary<string, object> values = null)
        {
            this.generatorType = typeof(TGeneratorType);

            this.GenerateFile(fileInfo, _namespace, values);
        }

        public void GenerateFile(FileInfo fileInfo, string _namespace, Dictionary<string, object> values = null)
        {
            try
            {
                var generator = Activator.CreateInstance(generatorType);
                var session = new TextTemplatingSession();

                session["Name"] = Path.GetFileNameWithoutExtension(fileInfo.Name);
                session["Namespace"] = _namespace;

                if (values != null)
                {
                    session["Values"] = values;
                }

                generatorType.GetProperty("Session").SetValue(generator, session, null);
                generatorType.GetMethod("Initialize").Invoke(generator, null);

                var output = (string)generatorType.GetMethod("TransformText").Invoke(generator, null);

                var stream = fileInfo.OpenWrite();
                var writer = new StreamWriter(stream);

                writer.Write(output);
                writer.Flush();

                writer.Close();
                stream.Close();
            }
            catch (Exception ex)
            {
                Debugger.Break();
            }
        }


        public void GenerateFile<TGeneratorType>(FileInfo fileInfo, string _namespace, IEnumerable list = null)
        {
            this.generatorType = typeof(TGeneratorType);

            this.GenerateFile(fileInfo, _namespace, list);
        }

        public void GenerateFile(FileInfo fileInfo, string _namespace, IEnumerable list = null)
        {
            try
            {
                var generator = Activator.CreateInstance(generatorType);
                var session = new TextTemplatingSession();

                session["Namespace"] = _namespace;
                session["Name"] = Path.GetFileNameWithoutExtension(fileInfo.Name);

                if (list != null)
                {
                    session["List"] = list;
                }

                generatorType.GetProperty("Session").SetValue(generator, session, null);
                generatorType.GetMethod("Initialize").Invoke(generator, null);

                var output = (string)generatorType.GetMethod("TransformText").Invoke(generator, null);

                var stream = fileInfo.OpenWrite();
                var writer = new StreamWriter(stream);

                writer.Write(output);
                writer.Flush();

                writer.Close();
                stream.Close();
            }
            catch (Exception ex)
            {
                Debugger.Break();
            }
        }
    }
}
